/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework;

import java.io.Serializable;
import java.lang.reflect.Proxy;

import org.springframework.aop.SpringProxy;
import org.springframework.core.NativeDetector;
import org.springframework.util.ClassUtils;

/**
 * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
 * or a JDK dynamic proxy.
 *
 * <p>Creates a CGLIB proxy if one the following is true for a given
 * {@link AdvisedSupport} instance:
 * <ul>
 * <li>the {@code optimize} flag is set
 * <li>the {@code proxyTargetClass} flag is set
 * <li>no proxy interfaces have been specified
 * </ul>
 *
 * <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy,
 * or specify one or more interfaces to use a JDK dynamic proxy.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Sebastien Deleuze
 * @author Sam Brannen
 * @since 12.03.2004
 * @see AdvisedSupport#setOptimize
 * @see AdvisedSupport#setProxyTargetClass
 * @see AdvisedSupport#setInterfaces
 */
/* 
 * AopProxyFactory的子类，
 * 也是SpringAOP中唯一默认的实现类
 */
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	private static final long serialVersionUID = 7930414337282325166L;

	/** 
	 * 真正的创建代理，判断一些列条件，有自定义的接口的就会创建jdk代理，否则就是cglib
	 * @param config the AOP configuration in the form of an
	 * AdvisedSupport object
	 * @return
	 * @throws AopConfigException
	 */
	// ====== 走jdk? or 走Cglib?【关键方法】
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		/** 
		    这段代码用来判断选择哪种创建代理对象的方式
		    config.isOptimize()   是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false
		    config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false
		    hasNoUserSuppliedProxyInterfaces 目标类是否有接口存在且 只有一个接口的时候接口类型不是SpringProxy类型
		 */
		/**  ======
		     isOptimize:  是否对代理进行优化
			 isProxyTargetClass:  值为true，使用CGLIB代理，默认false
			 hasNoUserSuppliedProxyInterfaces: 接口是不是满足
			 1、如果长度为0；也就是接口为空，返回false
			 or(或的关系)
			 2、如果接口类型不是SpringProxy类型的；返回false
		 */
		// ====== 如果任意一个满足，走cglib代理，结果，特喵的，都不满足！
		/**  ######
		     如果ProxyFactory的isOptimize为true，Spring认为cglib比jdk动态代理要快
		     或者isProxyTargetClass为true，
		     或者被代理对象没有实现接口，
		     或者只实现了SpringProxy这个接口
		     那么则利用Cglib进行动态代理，但如果被代理类是接口，或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理
		     其他情况都会进行JDK动态代理，比如被代理类实现了除SpringProxy接口之外的其他接口
		     是不是在GraalVM虚拟机上运行
		 */
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			// 上面的三个方法有一个为true的话，则进入到这里
			// 从AdvisedSupport中获取目标类 类对象
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			//  判断目标类是否是接口 如果目标类是接口的话，则还是使用JDK的方式生成代理对象
			//  如果目标类是Proxy类型 则还是使用JDK的方式生成代理对象
			//Tips：
			// ====== 如果目标对象实现了接口，默认情况下会采用JDK动态代理,
			// ====== 但也可以通过配置（proxy-target-class=true）强制使用CGLIB
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
				// ====== jdk
				return new JdkDynamicAopProxy(config);
			}
			//  配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象
			// ====== cglib
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			//  使用JDK的提供的代理方式生成代理对象
			// ====== jdk代理,走这里！
			// ====== 注意，config里面藏着了我们上面筛出来的那些 advisor，
			// ====== 也就是切面方法（before，after……）
			// ====== 并且，它们已经排好了顺序
			return new JdkDynamicAopProxy(config); // ====== 【找到了！】new出来的代理对象
		}
	}

	/**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified
	 * (or no proxy interfaces specified at all).
	 */
	//  如果存在一个接口，还是SpringProxy类型的，就返回true，否则就是false
	// ====== 如果长度为0；也就是接口为空，返回false
	// ====== 如果接口类型不是SpringProxy类型的；返回false
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	}

}
